#include "stdafx.h"
#include "win_thread.h"
#include <process.h>

_SSL_BEGIN
_SSWINOSL_BEGIN

win_thread::win_thread()
{
	thread_ = NULL;
	thread_id_ = 0;
	runable_ = NULL;
}

win_thread::~win_thread()
{
	stop();
}

bool win_thread::start(thread_runable_interface *runable /*= NULL*/, size_t stack_size /*= 0*/)
{
	if(is_runing())
	{
		return false;
	}
	stop();

	runable_ = runable;
	thread_ = (HANDLE)_beginthreadex(NULL, stack_size, s_thread_proc,
		this, 0, &thread_id_);
	return thread_ != NULL;
}

bool win_thread::stop(unsigned long milliseconds /*= 5000*/)
{
	if(!is_runing())
	{
		if(thread_ != NULL)
		{
			CloseHandle(thread_);
			thread_ = NULL;
		}
		thread_id_ = 0;
		return true;
	}

	if((runable_ != NULL) ? runable_->stop_request() : stop_request())
	{
		if(join(milliseconds))
		{
			return true;
		}
	}

	TraceVW(_T("No StopRequest Interface, Sleep Begin"));
	TraceVW(_T("Will Terminate Thread[%d]!!! That may cause some issues, such as dead lock!"), thread_id_);

	TerminateThread(thread_, ~0);

	CloseHandle(thread_);
	thread_ = NULL;

	thread_id_ = 0;

	return true;
}

bool win_thread::join(unsigned long milliseconds /*= INFINITE*/, unsigned long *exit_code /*= NULL*/)
{
	if(thread_ == NULL)
	{
		TraceVE(_T("The Handle of thread is empty!"));
		return false;
	}

	TraceVT(_T("Before Wait Thread %d, Timeout=%d millisecond(s)"), thread_id_, milliseconds);
	unsigned long ret = WaitForSingleObject(thread_, milliseconds);
	TraceVT(_T("After Wait Thread"));
	if(ret != WAIT_OBJECT_0)
		return false;

	if(!GetExitCodeThread(thread_, &ret))
	{
		TraceVW(_T("GetExitCodeThread failed!"));
		ret = ~0;
	}
	if(exit_code != NULL)
		*exit_code = ret;

	CloseHandle(thread_);
	thread_ = NULL;

	thread_id_ = 0;

	return true;
}

HANDLE win_thread::detach()
{
	HANDLE thread = thread_;
	thread_ = NULL;
	thread_id_ = 0;
	return thread;
}

bool win_thread::suspend()
{
	if(!is_runing())
		return false;
	SuspendThread(thread_);
	return true;
}

bool win_thread::resume()
{
	if(!is_runing())
		return false;
	ResumeThread(thread_);
	return true;
}

bool win_thread::get_exitcode(unsigned long *exit_code)
{
	if(thread_ == NULL || exit_code == NULL)
		return false;
	return GetExitCodeThread(thread_, exit_code) ? true : false;
}


bool win_thread::is_runing()
{
	if(thread_ == NULL)
		return false;

	return WaitForSingleObject(thread_, 0) == WAIT_TIMEOUT;
}

unsigned int win_thread::run()
{
	return 0;
}

bool win_thread::stop_request()
{
	return false;
}

unsigned int __stdcall win_thread::s_thread_proc(void* param)
{
	win_thread *thiz = (win_thread*)param;
	SS_ASSERT(thiz != NULL);
	return (thiz->runable_ != NULL) ? thiz->runable_->run() : thiz->run();
}

_SSWINOSL_END
_SSL_END
